package org.midy.server;

import org.midy.infrastructure.DefaultInformationDistribution;
import org.midy.infrastructure.IOEventDrivenContainer;
import org.midy.infrastructure.tools.Logger;

import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.util.concurrent.CountDownLatch;

public class ServerMain {
    public static void main(String[] args) {
        final CountDownLatch statusAll = new CountDownLatch(1);
        /* 业务处理派发实现类 */
        DefaultInformationDistribution defaultInformationDistribution = new DefaultInformationDistribution();
        /* 初始化一个循环事件组，用来处理IO事件监听 */
        IOEventDrivenContainer ioStreamContainer = new IOEventDrivenContainer("ReadWriteContainer", 10, defaultInformationDistribution, null);
        /* 初始化一个循环事件组，用来处理连接事件，需要关联到另外一个循环事件组 */
        IOEventDrivenContainer acceptContainer = new IOEventDrivenContainer("AcceptConnetContainer", 1, defaultInformationDistribution, ioStreamContainer);
        /* 初始化一个Socket服务端开启端口监听 */
        int listerPort = 5058;          // 服务端监听端口
        int milliseconds = 10 * 1000;   // 连接超时、闲置时间
        ServerSocketChannel serverSocketChannel = initServerSocketChannel(listerPort, milliseconds);
        /* Socket Server 开启异步事件驱动监听 */
        acceptContainer.allocation(serverSocketChannel, SelectionKey.OP_ACCEPT);
        /* 主线程等待 */
        waitMain(statusAll);
    }

    public static void waitMain(CountDownLatch statusAll) {
        if (statusAll == null) {
            return;
        }

        try {
            statusAll.await();
        } catch (InterruptedException e) {
            Logger.warn("主线程中断异常：" + e.getMessage());
        }
    }

    /**
     * 初始化一个 ServerSocketChannel 开启端口监听
     *
     * @param port    监听端口
     * @param timeout 连接超时时间
     * @return 初始化完毕的服务端
     */
    public static ServerSocketChannel initServerSocketChannel(int port, int timeout) {
        try {
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.socket().setReuseAddress(true);
            serverSocketChannel.configureBlocking(false);
            if (timeout > 0) {
                serverSocketChannel.socket().setSoTimeout(timeout); // 连接超时时间
            }
            ServerSocketChannel bindServerSocketChannel = serverSocketChannel.bind(new InetSocketAddress(port));
            Logger.info("lister port：" + port);
            return bindServerSocketChannel;
        } catch (Throwable throwable) {
            throw new RuntimeException(throwable);
        }
    }
}
